/**
 * WTF Engine
 *
 * License... etc.
 **
 * WTF Network Protocol
 **
 * Author: Sean Micklethwaite
 **/

#ifndef __net_protocolH__
#define __net_protocolH__

#include "interop.h"
#include <string.h>

namespace WtfEngine {
	VALUECLASS struct PacketData {
		static const unsigned int MAGIC = (((unsigned int)'W' << 24) + ((unsigned int)'T' << 16) + ((unsigned int)'F' << 8) + ((unsigned int)'1'));

		typedef enum {
			/// The type of the packet is MessagePacket
			PACKET_MESSAGE = 1,
			/// EventPacket - fires an event on the target
			PACKET_EVENT = 2,
			/// Contains game object update data
			PACKET_UPDATE = 3,
			/// Script command (requires privileged access)
			PACKET_PRIVILEGED_COMMAND = 4
		} tPacketType;

		/// Every packet must start with the MAGIC value defined above
		unsigned int	Magic;
		unsigned		PacketSize;
		tPacketType		PacketType;

		/// Node ID assigned to this node by the remote peer
		unsigned		NodeId;

		inline PacketData(tPacketType type, unsigned size): Magic(MAGIC), PacketSize(size), PacketType(type) {
		};

		inline bool isValidPacket() const {
			return (Magic == MAGIC);
		};
	};

	VALUECLASS struct MessagePacket : public PacketData {
		typedef enum {
			/// The acknowledge message is sent after a message which needs acknowledgement, to
			/// confirm that it has been recieved
			MSG_ACK = 1,

			/// Sent by clients after connection
			MSG_INTRODUCTION,

			MSG_PING, MSG_PONG,

			/// Broadcasting to find a party for a game - the initial stage
			/// in matchmaking
			MSG_PARTY_BROADCAST,

			/// Details of the current/updated party, sent to party guests and other
			/// party leaders when matchmaking
			MSG_PARTY_DETAILS,
			
			MSG_START_TRANSACTION,
			MSG_CONFIRM_TRANSACTION,
			MSG_FINALIZE_TRANSACTION,
			MSG_ABORT_TRANSACTION,

			/// Request privlileged access
			MSG_REQUEST_PRIVILEGED_ACCESS
		} tMessageType;

		tMessageType	MessageType;

		inline MessagePacket(tMessageType type, unsigned uSize = sizeof(MessagePacket))
		: PacketData(PACKET_MESSAGE, uSize), MessageType(type) 
		{
		};
	};

	VALUECLASS struct IntroductionMessage: public MessagePacket {
		unsigned short wDataPort;

		inline IntroductionMessage()
		: MessagePacket(MSG_INTRODUCTION, sizeof(IntroductionMessage)) {
		};
	};

	VALUECLASS struct PartyBroadcastMessage : public MessagePacket {
		unsigned uCurrentPartySize, uMinPartySize, uMaxPartySize;
		/// A special value indicating which game is being played
		unsigned uGameId;
		/// A value identifying the type of game searched for
		int      iGameType;

		unsigned short wControlPort;
		unsigned short wDataPort;

		inline PartyBroadcastMessage(unsigned uSize = sizeof(PartyBroadcastMessage))
		: MessagePacket(MSG_PARTY_BROADCAST, uSize) {
		};
	};

	
	/**
	 * Header of the party details message packet. Member descriptors
	 * follow this header.
	 **/
	VALUECLASS struct PartyDetailsMessage : public MessagePacket {
		unsigned uCurrentPartySize;
		unsigned uMemberDescriptorSize;

		/**
		 * Basic party member structure. This can be extended with additional
		 * game-specific information
		 **/
		struct Entry {
			/// Display name of the player
			/// TODO: replace with string hash
			char sName[32];

			/// IP Address
			unsigned Address;

			/// TCP control port
			unsigned short ControlPort;

			/// UDP data port
			unsigned short DataPort;
		};

		inline PartyDetailsMessage(unsigned uMembers, unsigned uMemberSize)
		: MessagePacket(MSG_PARTY_DETAILS, sizeof(PartyDetailsMessage) + (uMemberSize * uMembers)),
		  uCurrentPartySize(uMembers), uMemberDescriptorSize(uMemberSize)
		{
		};
	};


	VALUECLASS struct UpdatePacket: public PacketData {

	};

	/**** Command Packets ****/

	/**
	 * Executes a script on the remote peer (requires privileged access). The
	 * script follows this header.
	 **/
	VALUECLASS struct CommandPacket : public PacketData {
		inline CommandPacket(unsigned uSize)
			: PacketData(PACKET_PRIVILEGED_COMMAND, sizeof(CommandPacket) + uSize)
		{ };
	};
};

#endif
